# coding=utf-8
from flask import Flask, request, redirect, jsonify
from flask import make_response, render_template
import logging
import random
import redis
import pickle
import time
import uuid
import Customer
import SMS_Send

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=1)  # redis 连接池，所有数据保存在redis里
r = redis.Redis(connection_pool=pool)
"""
day1_coin_account = 0  # 活动每天发币的总量 1,2,3
day2_coin_account = 0
day3_coin_account = 0
hour_coin_account = 0  # 每小时应发出去币的量，0-8小时不发，等于每天的总量/16
hour_coin_out = 0  # 每小时发出币的数量，各个小时段量不一样，数据库保存多份（16*3）

如：hour9_coin_out1,hour10_coin_out1,.......
    hour9_coin_out2,hour10_coin_out2,.......
    hour9_coin_out3,hour10_coin_out3,.......
    day1_coin = 10  # 活动每天没签到一次发币的数量 1,2,3
    day2_coin = 20
    day3_coin = 50
"""
start_date = "2018-06-04"  # 发币开始的日期 需要提前定义好

app = Flask(__name__)


@app.route('/Hi')
def hello_world():  # this is for test
    response = make_response(render_template('test.html', result="have"))
    _uid = uuid.uuid1()
    response.set_cookie('Name', str(_uid))
    response.delete_cookie('Name')
    return redirect('http://www.baidu.com')


"""
  描述：获取短信验证码  /backend/get_sms_code
  type:get
  args:{
  mobile  : 手机号
    }
  return:
  result: 1 "短信发送成功" 2 "短信发送失败"  
"""
@app.route('/backend/get_sms_code', methods=['GET'])
def get_sms_code():
    # 接受前端发来的数据
    data = request.args
    mobile = data['mobile']
    logging.info("get_sms_code interface: " + mobile)
    info = dict()
    info['error'] = 0
    info['msg'] = "success"
    result = 0
    if mobile != ''and len(mobile) == 11 and is_mobile_num(mobile):
        _busess_id = uuid.uuid1()
        _sign_name = "SCTech"
        _template_code = "SMS_136161107"
        _sms_code = get_random_code()
        # 给输入的手机号发送短信验证码
        try:
            params = {"code": _sms_code}
            logging.info("get_sms_code interface: mobile-" + mobile+" sms_code-"+_sms_code)
            SMS_Send.send_sms(_busess_id, mobile, _sign_name, _template_code, params)
            save_sms_code(mobile, _sms_code)
            result = 1
        except Exception:
            info['error'] += 1
            info['msg'] = "sms_send_failed"
            logging.warning("get_sms_code interface: sms_send_failed")
            result = 2
    else:
        info['error'] += 1
        info['msg'] = "mobile num error"
        logging.error("get_sms_code interface: mobile num error")
    info['data'] = [{'result': result}]
    return jsonify(info)


"""
  描述：绑定ETH  /backend/bind_eth
  type:get
  args:{
     eth_address: eth 地址
    }
  return:  
  result:  0 "绑定成功" 1 "eth地址或手机重复,不对应"
  uuid: 用户的UUID 保存cookie，
"""
@app.route('/backend/bind_eth', methods=['POST'])
def bind_eth():  # 绑定ETH地址
    # 接受前端发来的数据
    ETH_Address = request.form['eth_address']
    mobile = request.form['mobile']
    num = get_day_num()
    uddd = ''
    result = 0
    info = dict()
    info['error'] = 0
    info['msg'] = "success"
    if ETH_Address != '':
        if num == 1 or num == 2 or num == 3:
            if check_is_same_mobile_ETH(mobile, ETH_Address):  # 验证码通过，登录成功, 保存cookie
                logging.info("bind eth interface : mobile-" + mobile + " ETH_address-" + ETH_Address)
                update_user_eth(mobile, ETH_Address)
                result = 0
            else:
                result = 1
        else:
            info['error'] += 1
            info['msg'] = "failed"
    else:
        info['error'] += 1
        info['msg'] = "ETH address error"
        logging.error("bind eth interface : ETH address error")
    info['data'] = [{'result': result, 'uuid': uddd}]
    return jsonify(info)


"""
  描述：登录接口  /backend/login
  type:get
  args:{
     mobile : 手机号码
     sms_code: 验证码
    }
  return:  
  result:  0 "登录成功" 1 "需要输入ETH地址", 2 "验证码不正确"
  uuid: 用户的UUID 保存cookie，
  eth_address: ETH地址
"""
@app.route('/backend/login', methods=['POST'])
def login():  # 使用短信验证码登录
    # 接受前端发来的数据
    mobile = request.form['mobile']
    sms_code = request.form['sms_code']
    logging.info("login interface : mobile-" + mobile + " sms_code-" + sms_code)
    num = get_day_num()
    result = 0
    ETH_Address = ''
    uddd = ''
    info = dict()
    info['error'] = 0
    info['msg'] = "success"
    if mobile != '' and len(mobile) == 11 and is_mobile_num(mobile):
        if num == 1 or num == 2 or num == 3:
            if sms_code == get_sms_code_from_redis(mobile):  # 验证码通过，登录成功, 保存cookie
                if check_user_is_in_redis(mobile):
                    ETH_Address, uddd = get_ETH_by_mobile(mobile)
                    if ETH_Address != '':
                        result = 0
                    else:
                        result = 1
                else:
                    result = 1
                    uddd = uuid.uuid1()
                    save_user_info(mobile, ETH_Address, uddd)
                save_cookie(mobile, ETH_Address, uddd)
                delete_sms_code(mobile)
            else:
                result = 2   # 验证码输入不正确,重新验证
        else:
            info['error'] += 1
            info['msg'] = "failed"
    else:
        info['error'] += 1
        info['msg'] = "mobile num error"
        logging.error("login interface :mobile num error")
    info['data'] = [{'result': result, 'uuid': uddd}]
    return jsonify(info)


"""
  描述：点击签到的接口，判断是否已签到，是否有币发放  /backend/register
  type:get
  args:{
    }
  return data:
  result: 11 "有币发放，签到成功" 12 "无币发放，签到失败" 13 "已经签到过了" 14 "需要重新绑定ETH"
  register_num: 签到次数
  coin_count:  领币数量
  get_coin_num: 当天签到获得的币数
  eth_address: ETH地址
"""
@app.route('/backend/register', methods=['POST'])
def register():
    uid = request.cookies.get('uuid')  # 取cookie
    mobile, ETH_Address = get_mobile_ETH_from_uid(uid)
    num = get_day_num()
    result = 0
    get_coin_num = 0
    info = dict()
    info['error'] = 0
    info['msg'] = "success"
    logging.info("register interface uid is : ", uid)
    logging.info("register interface the num is: ", num)
    logging.info("register interface mobile is : ", mobile)
    logging.info("register interface ETH address is: ", ETH_Address)
    if ETH_Address != '' and len(ETH_Address) == 42:
        if num == 1 or num == 2 or num == 3:
            if is_register_mobile(num, mobile):
                result = 13  # 已经签到过
            else:
                if is_have_coin(num):  # 记录发币，保存cookie,保存信息
                    register_count = get_register_num(mobile)
                    distr_coin(register_count, num)  # 记录发币数据
                    get_coin = save_coin(num, mobile, ETH_Address)
                    if num == 3:
                        get_coin_num = get_coin
                    elif num == 2:
                        get_coin_num = get_coin
                    elif num == 1:
                        get_coin_num = get_coin
                    result = 11  # 有cookie有币可发，签到成功
                else:
                    result = 12  # 有cookie没币可发，签到失败
        else:
            info['error'] += 1
            info['msg'] = "failed"
            logging.error("register interface : failed!")
    else:
        result = 14  # ETH地址为空，需要重新绑定
    day1_signed, day2_signed, day3_signed, register_num, coin_count = get_register_num_from_mobile(mobile)
    eth_str = ETH_Address[0:4] + "...." + ETH_Address[-3:]
    logging.info("register interface: eth_address-"+ETH_Address+" register num-"+
                 str(register_num)+" coin count-"+str(coin_count))
    if day1_signed and day2_signed and day3_signed:
        get_coin_num += 100
    info['data'] = [{'result': result, 'get_coin_num': get_coin_num, 'eth_address': eth_str,
                     'register_num': register_num, 'coin_count': coin_count}]
    return jsonify(info)



"""
  描述：活动是否开始，根据cookie判断是否登录状态
  type:get
  args:{
    }
  return:
  result: >3 "签到倒计时" 2 "签到活动第一天" 1 "签到活动第二天" 0 "签到活动第三天" -1 "签到活动已结束"  
"""
@app.route('/', methods=['GET'])
def index():   # 首次加载页面，显示签到次数和获得的SCKT的数量
    uid = request.cookies.get('uuid')  # 取cookie
    logging.info("index : start_date-"+start_date)
    num = get_day_num()
    if num > 3:  # 活动未开始
        return render_template('warm.html', num=num, start_date=start_date)
    elif num == -1:  # 活动已结束
        return redirect('https://www.shareschain.net/index-zh.html')
    else:  # 活动进行中
        if uid is None or uid == '' or not check_cookie_uuid(uid):  # 无cookie 需要登录
            return render_template("login.html", num=num, start_date=start_date)
        else:  # 有cookie
            mobile, ETH_Address = get_mobile_ETH_from_uid(uid)
            eth_str = ETH_Address[0:4]+"...."+ETH_Address[-3:]
            day1_signed, day2_signed, day3_signed, register_num, coin_count = get_register_num_from_mobile(mobile)
            return render_template('sign.html', num=num, start_date=start_date, register_num=register_num,
                                   coin_count=coin_count, eth=eth_str,
                                   day1_signed=day1_signed, day2_signed=day2_signed, day3_signed=day3_signed)


def get_day_num():  # 根据当前时间判断发币倒计时， 返回 7,6,5,5,4,3,2,1,0，-1
    strNow = time.strftime("%Y-%m-%d")
    strStart = time.strptime(start_date, "%Y-%m-%d")
    strN = time.strptime(strNow, "%Y-%m-%d")
    if strN[1] == 1 or strN[1] == 3 or strN[1] == 5 or strN[1] == 7 or strN[1] == 8 or strN[1] == 10 or strN[1] == 12:
        monday = 31
    elif strN[1] == 2:  # 将2月定义为28天了
        monday = 28
    else:
        monday = 30
    if strStart[1] >= strN[1]:  # 月份对比
        strdif = (strStart[1] - strN[1]) * monday + strStart[2] - strN[2]  # 天数差
        if strdif < 1:
            return -1
        else:
            return strdif
    else:
        # print("活动已过期")
        return -1


def is_mobile_num(mobile_str):  # 是否是规格的手机号
    import re
    p2 = re.compile('^1\d{10}')
    phone_match = p2.match(mobile_str)
    if phone_match:
        return True
    else:
        return False


def get_register_num(mobile_str):
    user = pickle.loads(r.get(mobile_str))
    login_count = user.get_num
    return login_count


def check_user_is_in_redis(str_key):  # 判断用户是否存在于redis
    if r.get(str_key) is None:
        # print('没有该用户信息')
        return False
    else:
        return True


def check_is_same_mobile_ETH(mobile_str, eth_address_str):  # 检查手机号和ETH地址是否一一对应,如果redis没有新加认为是一一对应的
    if r.get(mobile_str) is not None and r.get(eth_address_str) is not None:
        str_eth = pickle.loads(r.get(mobile_str)).eth_address
        str_mobile = pickle.loads(r.get(eth_address_str)).mobile_num
        if str_eth == eth_address_str and str_mobile == mobile_str:
            return True
        else:
            return False
    else:
        return True


def save_sms_code(mobile_str, code_str):  # 保存短信验证码，用于登录验证
    mobile_str += '_sms_code'
    if r.get(mobile_str) is not None:
        r.delete(mobile_str)
    r.set(mobile_str, code_str)


def delete_sms_code(mobile_str):  # 登录成功后，需要redis删除短信验证码
    mobile_str += '_sms_code'
    r.delete(mobile_str)


def get_sms_code_from_redis(mobile_str):  # 取出短信验证码，验证登录
    mobile_str += '_sms_code'
    if r.get(mobile_str) is None:
        return ""
    else:
        return str(r.get(mobile_str), encoding="utf-8")


def save_user_info(mobile_str, eth_address_str, uid_str):  # 登录成功保存用户信息
    user = Customer.Customer(mobile_str, eth_address_str)
    user.uid = uid_str
    r.set(mobile_str, pickle.dumps(user))


def update_user_eth(mobile_str, eth_address_str):  # 新加ETH地址保存redis
    user = pickle.loads(r.get(mobile_str))
    user.eth_address = eth_address_str
    r.set(mobile_str, pickle.dumps(user))
    r.set(eth_address_str, pickle.dumps(user))
    r.set(user.uid, pickle.dumps(user))


def save_coin(daynum, mobile_str, eth_address_str):  # 签到成功保存用户签到信息
    user = pickle.loads(r.get(mobile_str))
    login_count = user.get_num
    day1_coin = int(r.get('day1_coin'))
    day2_coin = int(r.get('day2_coin'))
    day3_coin = int(r.get('day3_coin'))
    get_coin = 0

    if login_count == 0:
        user.coin_count += day1_coin
        get_coin = day1_coin
        if daynum == 3:
            user.get_one = True
        elif daynum == 2:
            user.get_two = True
        else:
            user.get_three = True
    elif login_count == 1:
        get_coin = day2_coin
        user.coin_count += day2_coin
        if daynum == 2:
            user.get_two = True
        else:
            user.get_three = True
    elif login_count == 2:
        get_coin = day3_coin
        user.coin_count += day3_coin
        user.coin_count += 100
        user.get_three = True

    login_count += 1
    user.get_num = login_count  # 签到次数
    r.set(mobile_str, pickle.dumps(user))
    r.set(eth_address_str, pickle.dumps(user))
    return get_coin


def save_cookie(str_mobile, str_eth, str_uid):
    if r.get(str_mobile) is not None:
        user = pickle.loads(r.get(str_mobile))
    else:
        user = Customer.Customer(str_mobile, str_eth)
    r.set(str_uid, pickle.dumps(user))  # 保存cookie


def check_cookie_uuid(udd):  # 检查是否保存cookie
    if r.get(udd) is None:
        # print('没有cookie')
        return False
    else:
        return True


def get_ETH_by_mobile(mobile_str):  # 根据mobile取出mobile和uid
    str_ETH, str_uid = '', ''
    if r.get(mobile_str) is not None:
        user = pickle.loads(r.get(mobile_str))
        str_ETH = user.eth_address
        str_uid = user.uid
    return str_ETH, str_uid


def get_mobile_ETH_from_uid(udd):  # 根据UID取出mobile和ETH
    str_mobile, str_ETH = '', ''
    if r.get(udd) is not None:
        user = pickle.loads(r.get(udd))
        str_mobile = user.mobile_num
        str_ETH = user.eth_address
    return str_mobile, str_ETH


def get_register_num_from_mobile(mobile_str):  # 根据mobile获取签到次数和OCKT 数量
    register_nn, coin_cc = 0, 0
    day1_signed, day2_signed, day3_signed = False, False, False
    if r.get(mobile_str) is not None:
        rr = r.get(mobile_str)
        user = pickle.loads(rr)
        register_nn = user.get_num
        coin_cc = user.coin_count
        if register_nn == 1:
            day1_signed = True
        elif register_nn == 2:
            day1_signed = True
            day2_signed = True
        elif register_nn == 3:
            day1_signed = True
            day2_signed = True
            day3_signed = True
    return day1_signed, day2_signed, day3_signed, register_nn, coin_cc


def is_register_ETFaddress(daynum, ETH_address_str):  # 判断用户(ETH号)是否领过币 daynum 发币倒计时
    if r.get(ETH_address_str) is not None:
        if daynum == 3:
            if pickle.loads(r.get(ETH_address_str)).get_one:
                return False
            else:
                return True
        elif daynum == 2:
            if pickle.loads(r.get(ETH_address_str)).get_two:
                return False
            else:
                return True
        else:
            if pickle.loads(r.get(ETH_address_str)).get_three:
                return False
            else:
                return True
    else:
        return False


def is_register_mobile(daynum, mobile_str):  # 判断用户(手机号)是否领过币, daynum 发币倒计时
    if r.get(mobile_str) is not None:
        if daynum == 3:
            return pickle.loads(r.get(mobile_str)).get_one
        elif daynum == 2:
            return pickle.loads(r.get(mobile_str)).get_two
        else:
            return pickle.loads(r.get(mobile_str)).get_three
    else:
        return False


def is_have_coin(daynum):  # 按活动天数判断是否有币发放，daynum = 1,2,3,
    now_hour = time.localtime().tm_hour
    hour_str = ""
    hour_coin_balance = 0
    if daynum != 1 and daynum != 2 and daynum != 3:
        return False  # 不是签到活动日期内，不发币
    if now_hour >= 0 and now_hour < 8:
        # print("该时间段没有币可发")
        return False
    else:
        if daynum == 3:  # 签到活动第一天
            hour_coin_account = int(r.get('day1_coin_account'))/16
            hour_str = "hour"+str(now_hour)+"_coin_out1"
            hour_coin_balance = hour_coin_account - int(r.get(hour_str))
            print(hour_coin_balance)
            if hour_coin_balance >= int(r.get('day1_coin')):
                return True
            else:
                return False
        elif daynum == 2:  # 签到活动第二天
            hour_coin_account = int(r.get('day2_coin_account'))/16
            hour_str = "hour" + str(now_hour) + "_coin_out2"
            hour_coin_balance = hour_coin_account - int(r.get(hour_str))
            if hour_coin_balance >= int(r.get('day2_coin')):
                return True
            else:
                return False
        else:  # 签到活动第三天
            hour_coin_account = int(r.get('day3_coin_account'))/16
            hour_str = "hour" + str(now_hour) + "_coin_out3"
            hour_coin_balance = hour_coin_account - int(r.get(hour_str))
            if hour_coin_balance >= int(r.get('day3_coin'))+100:
                return True
            else:
                return False


def distr_coin(daynum, num):  # 按按发币倒计时天数 增加每个小时的发币量
    now_hour = time.localtime().tm_hour
    daynum += 1
    if num == 3:
        str_tmp = "hour" + str(now_hour) + "_coin_out1"
    elif num == 1:
        str_tmp = "hour" + str(now_hour) + "_coin_out3"
    else:
        str_tmp = "hour" + str(now_hour) + "_coin_out2"

    day1_coin = int(r.get('day1_coin'))
    day2_coin = int(r.get('day2_coin'))
    day3_coin = int(r.get('day3_coin'))
    if daynum == 1:
        r.incrby(str_tmp, day1_coin)
    elif daynum == 2:
        r.incrby(str_tmp, day2_coin)
    else:
        r.incrby(str_tmp, day3_coin)
        r.incrby(str_tmp, 100)


def send_sms(mobile_str):  # 需要给发短信的参数定义值
    _busess_id = uuid.uuid1()
    _sign_name = ""
    _template_code = ""
    result = ""
    SMS_Send.send_sms(_busess_id, mobile_str, _sign_name, _template_code)
    return result  # 返回短信验证码


#随机生成6个数字
def get_random_code():
    sms_code = ''
    for i in range(6):
        tmp = random.randrange(0, 9)
        sms_code += str(tmp)
    print(sms_code)
    return sms_code


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)
